package edu.umb.cs.antmanager.manager;

import java.awt.*;
import java.awt.event.*;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import edu.umb.cs.antmanager.common.AgentControlIntFace;
import edu.umb.cs.antmanager.domain.MachineType;

import static edu.umb.cs.antmanager.common.Constants.*;

/**
 * Main control GUI, can do basic system monitor and maintain job
 * 
 * @author Zachary
 * 
 */
public class ManagerControlGUI extends JFrame {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private JList machineList;
	private JButton statusButton;
	private JButton shutdownButton;
	private JButton restartButton;
	private JButton startButton;
	private JButton logButton;
	private JTextArea resultTextArea;
	private JTextField cmdField;
	private JButton executeButton;
	private JPanel cmdPanel;

	/**
	 * Create the GUI
	 */
	public ManagerControlGUI() {
		super();

		refreshMachineList();
		createButtons();
		resultTextArea = new JTextArea(15, 50);
		resultTextArea.setEditable(false);
		JScrollPane resultScrollPane = new JScrollPane(resultTextArea);
		JScrollPane agentListScroller = new JScrollPane(machineList);
		resultScrollPane
				.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
		cmdField = new JTextField(30);

		JPanel mainPanel = new JPanel();
		mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
		mainPanel.add(new JLabel("Machine List"));
		mainPanel.add(agentListScroller);

		cmdPanel = new JPanel();
		cmdPanel.setLayout(new BoxLayout(cmdPanel, BoxLayout.X_AXIS));
		cmdPanel.add(new JLabel("Command:"));
		cmdPanel.add(cmdField);
		cmdPanel.add(executeButton);
		mainPanel.add(cmdPanel);
		mainPanel.add(Box.createRigidArea(new Dimension(0, 10)));

		JPanel btnPanel = new JPanel();
		btnPanel.setLayout(new BoxLayout(btnPanel, BoxLayout.X_AXIS));
		btnPanel.add(statusButton);
		btnPanel.add(Box.createRigidArea(new Dimension(15, 0)));
		btnPanel.add(logButton);
		btnPanel.add(Box.createRigidArea(new Dimension(15, 0)));
		btnPanel.add(shutdownButton);
		btnPanel.add(Box.createRigidArea(new Dimension(15, 0)));
		btnPanel.add(restartButton);
		btnPanel.add(Box.createRigidArea(new Dimension(15, 0)));
		btnPanel.add(startButton);
		mainPanel.add(btnPanel);

		mainPanel.add(Box.createRigidArea(new Dimension(0, 10)));
		mainPanel.add(new JLabel("Result"));
		mainPanel.add(resultScrollPane);
		mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

		this.setContentPane(mainPanel);
		setCmdExeVisible(false);
	}

	private void createButtons() {
		ButtonActionListener bl = new ButtonActionListener();
		statusButton = new JButton("Get Status");
		statusButton.setActionCommand("status");
		statusButton.addActionListener(bl);

		shutdownButton = new JButton("Shutdown");
		shutdownButton.setActionCommand("shutdown");
		shutdownButton.addActionListener(bl);

		restartButton = new JButton("Restart");
		restartButton.setActionCommand("restart");
		restartButton.addActionListener(bl);

		executeButton = new JButton("Execute");
		executeButton.setActionCommand("execute");
		executeButton.addActionListener(bl);

		startButton = new JButton("Start");
		startButton.setActionCommand("start");
		startButton.addActionListener(bl);

		logButton = new JButton("Live Log");
		logButton.setActionCommand("log");
		logButton.addActionListener(bl);
	}

	private void updateMachineStatus() {
		Object[] selectedMachines = machineList.getSelectedValues();
		resultTextArea.setText("");
		for (Object o : selectedMachines) {
			new Thread(
					new AgentTaskRunner(o.toString(), this, TASK_TYPE_STATUS))
					.start();
		}
	}

	private void runTask(int type) {
		Object[] selectedMachines = machineList.getSelectedValues();
		resultTextArea.setText("");
		for (Object o : selectedMachines) {
			new Thread(new AgentTaskRunner(o.toString(), this, type)).start();
		}
	}

	private void excuteCommand() {
		Object[] selectedMachines = machineList.getSelectedValues();
		resultTextArea.setText("");
		if (selectedMachines.length != 1) {
			setResultText("You can only execute command on one agent");
		} else {
			new Thread(new AgentTaskRunner(selectedMachines[0].toString(),
					this, TASK_TYPE_EXECUTE, cmdField.getText())).start();

		}
	}

	private class ButtonActionListener implements ActionListener {
		public void actionPerformed(ActionEvent e) {
			if (machineList.getSelectedIndices().length <= 0) {
				setResultText("Please select one or more machines!");
				return;
			}
			if (e.getActionCommand().equals("status"))
				updateMachineStatus();
			else if (e.getActionCommand().equals("shutdown"))
				runTask(TASK_TYPE_SHUTDOWN);
			else if (e.getActionCommand().equals("restart"))
				runTask(TASK_TYPE_RESTART);
			else if (e.getActionCommand().equals("execute"))
				excuteCommand();
			else if (e.getActionCommand().equals("start")) {
				SwingUtilities.invokeLater(new Runnable() {
					public void run() {
						Object[] selectedMachines = machineList
								.getSelectedValues();
						resultTextArea.setText("");
						for (Object o : selectedMachines) {
							try {
								AgentControlIntFace ac = (AgentControlIntFace) Naming
										.lookup("rmi://" + o.toString() + ":"
												+ CONTROL_PORT + "/"
												+ AGENT_CONTROLLER);
								ac.start();
								appendResultText("Start agent " + o.toString());
							} catch (MalformedURLException e) {
								e.printStackTrace();
							} catch (RemoteException e) {
								System.err.println(e.getMessage());
								appendResultText("Cannot connect AgentDispatcher!");
							} catch (NotBoundException e) {
								System.err.println(e.getMessage());
								appendResultText("Cannot connect AgentDispatcher!");
							}
						}
					}
				});
			} else if (e.getActionCommand().equals("log")) {
				runTask(TASK_TYPE_LOG);
			}
		}
	}

	private class AgentSelectionListener implements ListSelectionListener {

		@Override
		public void valueChanged(ListSelectionEvent e) {
			Object[] o = machineList.getSelectedValues();
			if (o.length > 0) {
			}
			if (o.length == 1) {
				setCmdExeVisible(true);
			} else {
				setCmdExeVisible(false);
			}
		}

	}

	private void refreshMachineList() {
		DefaultListModel listModel = new DefaultListModel();
		ResourceManager.getResourceManager().LoadMachines(
				ANT_MANAGER_HOME + "machines.xml", null);
		for (MachineType m : ResourceManager.getResourceManager().getMachines()) {
			listModel.addElement(m.getName());
		}
		machineList = new JList(listModel);
		machineList.setLayoutOrientation(JList.HORIZONTAL_WRAP);
		machineList.setFixedCellWidth(150);
		machineList.addListSelectionListener(new AgentSelectionListener());
	}

	private void setResultText(String result) {
		resultTextArea.setText(result);
		resultTextArea.repaint();
	}

	public void appendResultText(String msg) {
		resultTextArea.setText(resultTextArea.getText()
				+ System.getProperty("line.separator") + msg);
		resultTextArea.repaint();
	}

	private void setCmdExeVisible(boolean vis) {
		cmdPanel.setVisible(vis);
		pack();
	}

	/**
	 * Start the application
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		JFrame f = new ManagerControlGUI();
		f.setTitle("Ant Manager Control GUI");
		f.setMinimumSize(new Dimension(600, 400));
		f.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});

		f.pack();
		f.setVisible(true);
	}

}
